package Operations;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.LinkedHashMap;
import java.util.LinkedList;

import random.TestClusterBuilder;
import util.Filter;
import GA.ConstructorDeclared;
public class CreateObject extends Operation implements Cloneable{

	private  ConstructorDeclared constructor;
	public CreateObject(ConstructorDeclared constructor){
		this.constructor=constructor.clone();
	}
	public static Map<String, List<CreateObject>> generateInitialClass(TestClusterBuilder TestCluster) {
		Map<String, Class<?>> cluster = TestCluster.getCluster();
		Map<String, String[]> refFactory = TestCluster.getRefFactory();
		Map<String, ConstructorDeclared[]> clazzConstructors= TestCluster.getClazzConstructors();
	
		Map<String, List<CreateObject>> constructors= new LinkedHashMap <String, List<CreateObject>> ();
		
		List<String> refKeys = new ArrayList<String>(refFactory.keySet()); 
		for (int refIndx = 0; refIndx < refKeys.size(); refIndx++) {
			String cName = (String) refKeys.get(refIndx);
			if (!clazzConstructors.containsKey(cName))
				continue;
			// System.out.println("CreateObject.generate: "+ cName);
			String[] refrences = refFactory.get(cName);
			ConstructorDeclared[] cnsList = clazzConstructors.get(cName);
			// Constructor<?>[] cnsList=javaClass.getConstructors();
			for (int i = 0; i < refrences.length; i++) {
				if (cnsList.length == 0)
					continue;
				int randCons = ValuesGenerator.getRandomInt(cnsList.length);
				ConstructorDeclared cut = (ConstructorDeclared) cnsList[randCons]
						.clone();
				Class<?>[] paramsType = cut.getParameterTypes();
				Object[] actualParams = new Object[cut.getParameterTypes().length];
				String[] params = new String[paramsType.length];
				for (int k = 0; k < actualParams.length; k++) {
					if (Filter.isPrimitiveOrStringType(cluster
							.get(paramsType[k].getName().toString())))
						params[k] = ValuesGenerator.buildValue(paramsType[k]
								.getName());
					else
						params[k] = TestCluster.getReference(paramsType[k].getName(), refFactory);
				}
				cut.setRefrence(refrences[i]);
				cut.setParams(params);
				if (constructors.get(cName) == null)
					constructors.put(cName, new LinkedList<CreateObject>());
				List<CreateObject> constr = (List<CreateObject>) constructors
						.get(cName);
				constr.add(new CreateObject(cut));
			}

		}
		return constructors;
		}

	
	

	public static CreateObject generate(ConstructorDeclared c, TestClusterBuilder TestCluster){
		Map<String, Class<?>> cluster = TestCluster.getCluster();
		Map<String, String[]> refFactory = TestCluster.getRefFactory();
		
		if(c==null) return null;
		ConstructorDeclared cut= c.clone();
		
		Class<?>[] paramsType = cut.getParameterTypes();
		Object[] actualParams = new Object[cut.getParameterTypes().length];
		String[] params = new String[paramsType.length];
		for (int k = 0; k < actualParams.length; k++) {
		if (Filter.isPrimitiveOrStringType(cluster.get(paramsType[k].getName().toString())))
			params[k] = ValuesGenerator.buildValue(paramsType[k]
					.getName());
		else
			params[k] = TestCluster.getReference(paramsType[k].getName(), refFactory);
	}
		Class<?> clazz= cut.getClazz();
		String ref = getReference(clazz.getName(),refFactory);
		cut.setRefrence(ref);
		cut.setParams(params);
		
		return new CreateObject(cut);
	}
 public ConstructorDeclared getConstructor(){
	 return this.constructor;
 }
 public void setConstructor(ConstructorDeclared constructor){
	  this.constructor=constructor;
 }
 @Override
	public CreateObject clone() {
	 ConstructorDeclared constructorz=constructor.clone();
		final CreateObject clone = new CreateObject(constructorz);
		return clone;
	}
 @Override
	public String toString() {
	 return this.constructor.toString();
	 
 }
}